home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / UNIXTOOL / MEMACS / C / Riscos < prev    next >
Text File  |  1990-07-11  |  18KB  |  901 lines

  1. /*    RISCOS.C:    Operating specific I/O and Spawning functions
  2.             under the RISC OS operating system
  3.             for MicroEMACS 3.10
  4.             (C)opyright 1988 by Daniel M. Lawrence
  5. */
  6.  
  7. #include        <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10.  
  11. #ifdef    RISCOS
  12. #include        "edef.h"
  13. #include    "elang.h"
  14.  
  15. #include    <stdlib.h>
  16. #include    <time.h>
  17. #include    "filter.h"
  18. #include    "kernel.h"
  19. #include    "swis.h"
  20.  
  21. extern char *dirscan (char *);
  22.  
  23. static int bufread (BUFFER *, FILE *);
  24. static int fgetline (FILE *, char **, int *);
  25. static void shell (void);
  26. static int extchar (int, int);
  27.  
  28. /* Switch escape off and on, from C.Archimedes */
  29. extern void esc_off(void);
  30. extern void esc_on(void);
  31.  
  32. static _kernel_swi_regs regs;
  33.  
  34. #define fx(a,x,y)    (_kernel_osbyte(a,x,y))
  35. #define checkkey(k)    ((fx(121, (k) ^ 0x80, 0) & 0xFF) != 0)
  36. #define swi(n)        (_kernel_swi(n,®s,®s))
  37. #define vdu(n)        (void)(_kernel_oswrch(n))
  38.  
  39. #define vdu23(a,b,c,d,e,f,g,h,i) \
  40.     (void)( \
  41.     _kernel_oswrch(23), \
  42.     _kernel_oswrch(a), \
  43.     _kernel_oswrch(b), \
  44.     _kernel_oswrch(c), \
  45.     _kernel_oswrch(d), \
  46.     _kernel_oswrch(e), \
  47.     _kernel_oswrch(f), \
  48.     _kernel_oswrch(g), \
  49.     _kernel_oswrch(h), \
  50.     _kernel_oswrch(i)  \
  51.     )
  52.  
  53. /*    Some global variables    */
  54. #define INBUFSIZ    40
  55.  
  56. /*    input buffers and pointers    */
  57.  
  58. #define    IBUFSIZE    64    /* this must be a power of 2 */
  59.  
  60. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  61. int in_next = 0;        /* pos to retrieve next input character */
  62. int in_last = 0;        /* pos to place most recent input character */
  63.  
  64. void in_init (void)    /* initialize the input buffer */
  65. {
  66.     in_next = in_last = 0;
  67. }
  68.  
  69. int in_check (void)    /* is the input buffer non-empty? */
  70. {
  71.     if (in_next == in_last)
  72.         return(FALSE);
  73.     else
  74.         return(TRUE);
  75. }
  76.  
  77. void in_put (int event)
  78. {
  79.     in_buf[in_last++] = event;
  80.     in_last &= (IBUFSIZE - 1);
  81. }
  82.  
  83. int in_get (void)    /* get an event from the input buffer */
  84. {
  85.     register int event;    /* event to return */
  86.  
  87.     event = in_buf[in_next++];
  88.     in_next &= (IBUFSIZE - 1);
  89.     return(event);
  90. }
  91.  
  92. /* This function is called once to set up the terminal device streams.
  93.  */
  94.  
  95. int ttopen (void)
  96. {
  97.     ttrow = 999;
  98.     ttcol = 999;
  99.     in_init();
  100.     return 0;
  101. }
  102.  
  103. /* Write a character to the display. On VMS, terminal output is buffered, and
  104.  * we just put the characters in the big array, after checking for overflow.
  105.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  106.  * MS-DOS (use the very very raw console output routine).
  107.  */
  108.  
  109. int ttputc (int c)
  110. {
  111.     vdu(c);
  112.     return 0;
  113. }
  114.  
  115. /* Flush terminal buffer. Does real work where the terminal output is buffered
  116.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  117.  */
  118. int ttflush (void)
  119. {
  120.     return 0;
  121. }
  122.  
  123. /* Get a character from the operating system. If it is a special key code,
  124.  * return the initial 0 of the Emacs extended code, and push the remaining
  125.  * part of the code sequence into the input buffer.
  126.  */
  127. int oschar (void)
  128. {
  129.     int ch = _kernel_osrdch();
  130.     int alt = 0;
  131.  
  132.     /* Check for ALT */
  133.     if (ch == 0x7F)
  134.     {
  135.         alt = ALTD;
  136.         ch = _kernel_osrdch();
  137.     }
  138.  
  139.     /* For non-function keys, simply return them */
  140.     if (ch != 0 && alt == 0)
  141.         return ch;
  142.  
  143.     /* For ALT-normal keys, return 0, ALT, char (upper case) */
  144.     if (ch != 0)
  145.     {
  146.         in_put(alt >> 8);
  147.         in_put(upperc(ch));
  148.         return(0);
  149.     }
  150.  
  151.     /* Skip the null byte */
  152.     ch = _kernel_osrdch();
  153.  
  154.     /* A genuine null gets returned as 0, 0 */
  155.     if (ch == 0)
  156.     {
  157.         in_put(0);
  158.         return(0);
  159.     }
  160.  
  161.     /* For function keys, convert to an extended character */
  162.     ch = extchar(alt, ch);
  163.  
  164.     /* Check for a simple character */
  165.     if ((ch >> 8) == 0)
  166.         return(ch);
  167.  
  168.     /* Otherwise, return an extended sequence */
  169.     in_put(ch >> 8);
  170.     in_put(ch & 0xFF);
  171.     return(0);
  172. }
  173.  
  174. /* Read a character from the terminal, performing no editing and doing no echo
  175.  * at all. Also mouse events are forced into the input stream here.
  176.  */
  177. int ttgetc (void)
  178. {
  179.     register int c;        /* character read */
  180.  
  181.     /* return any keystrokes waiting in the type ahead buffer */
  182.     if (in_check())
  183.         return(in_get());
  184.  
  185.     return(oschar());
  186. }
  187.  
  188. #if    TYPEAH
  189. /* Check to see if any characters are already in the keyboard buffer.
  190.  */
  191. int typahead (void)
  192. {
  193.     int result;
  194.  
  195.     result = fx(152,0,0);
  196.  
  197.     if (result & 0x0F00)
  198.         return(FALSE);
  199.     else
  200.         return(TRUE);
  201. }
  202. #endif
  203.  
  204. /*
  205.  * Create a subjob with a copy of the command intrepreter in it. When the
  206.  * command interpreter exits, mark the screen as garbage so that you do a full
  207.  * repaint. Bound to "^X C".
  208.  */
  209.  
  210. int spawncli (int f, int n)
  211. {
  212.     /* don't allow this command if restricted */
  213.     if (restflag)
  214.         return(resterr());
  215.  
  216.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  217.         TTflush();
  218.     TTkclose();
  219.     shell();
  220.     TTkopen();
  221.         sgarbf = TRUE;
  222.         return(TRUE);
  223. }
  224.  
  225. /*
  226.  * Run a one-liner in a subjob. When the command returns, wait for a single
  227.  * character to be typed, then mark the screen as garbage so a full repaint is
  228.  * done. Bound to "C-X !".
  229.  */
  230. int spawn (int f, int n)
  231. {
  232.         register int s;
  233.         char line[NLINE];
  234.  
  235.     /* don't allow this command if restricted */
  236.     if (restflag)
  237.         return(resterr());
  238.  
  239.     strcpy(line, "Call:");
  240.  
  241.         if ((s=mlreply("!", &line[5], NLINE-5)) != TRUE)
  242.                 return(s);
  243.     movecursor(term.t_nrow - 1, 0);
  244.     TTkclose();
  245.         system(line);
  246.     TTkopen();
  247.     /* if we are interactive, pause here */
  248.     if (clexec == FALSE) {
  249.             mlputs(TEXT6);
  250. /*                     "\r\n\n[End]" */
  251.             tgetc();
  252.         }
  253.         sgarbf = TRUE;
  254.         return (TRUE);
  255. }
  256.  
  257. /*
  258.  * Run an external program with arguments. When it returns, wait for a single
  259.  * character to be typed, then mark the screen as garbage so a full repaint is
  260.  * done. Bound to "C-X $".
  261.  */
  262.  
  263. int execprg (int f, int n)
  264. {
  265.         register int s;
  266.         char line[NLINE];
  267.  
  268.     /* don't allow this command if restricted */
  269.     if (restflag)
  270.         return(resterr());
  271.  
  272.     strcpy(line, "Call:");
  273.  
  274.         if ((s=mlreply("$", &line[5], NLINE-5)) != TRUE)
  275.                 return(s);
  276.     movecursor(term.t_nrow - 1, 0);
  277.     TTkclose();
  278.         system(line);
  279.     TTkopen();
  280.     /* if we are interactive, pause here */
  281.     if (clexec == FALSE) {
  282.             mlputs(TEXT6);
  283. /*                     "\r\n\n[End]" */
  284.             tgetc();
  285.         }
  286.         sgarbf = TRUE;
  287.         return (TRUE);
  288. }
  289.  
  290. /*
  291.  * Pipe a one line command into a window
  292.  * Bound to ^X @
  293.  */
  294. int pipecmd (int f, int n)
  295. {
  296.     register WINDOW *wp;    /* pointer to new window */
  297.     register BUFFER *bp;    /* pointer to buffer to zot */
  298.     int s;            /* command status */
  299.         char line[NLINE];    /* command line send to shell */
  300.     FILTER *flt;        /* command filter */
  301.     static char bname[] = "command";
  302.  
  303.     /* don't allow this command if restricted */
  304.     if (restflag)
  305.         return(resterr());
  306.  
  307.     if ((flt = FLTopen()) == NULL)
  308.         return(FALSE);
  309.  
  310.     /* get the command to pipe in */
  311.         if (mlreply("@", line, NLINE) != TRUE)
  312.                 return(FALSE);
  313.  
  314.     /* get rid of the command output buffer if it exists */
  315.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  316.         /* try to make sure we are off screen */
  317.         wp = wheadp;
  318.         while (wp != NULL) {
  319.             if (wp->w_bufp == bp) {
  320.                 onlywind(FALSE, 1);
  321.                 break;
  322.             }
  323.             wp = wp->w_wndp;
  324.         }
  325.         /* get rid of the existing command buffer */
  326.         if (zotbuf(bp) != TRUE)
  327.             return(FALSE);
  328.     }
  329.  
  330.     movecursor(term.t_nrow - 1, 0);
  331.  
  332.     /* execute the command */
  333.     TTkclose();
  334.     s = FLTfilter(flt,line);
  335.     TTkopen();
  336.         sgarbf = TRUE;
  337.  
  338.         /* did the output file get generated? */
  339.     if (s == FILTER_ERROR)
  340.     {
  341.         FLTclose(flt);
  342.         return(FALSE);
  343.     }
  344.  
  345.     /* split the current window to make room for the command output */
  346.     if (splitwind(FALSE, 1) == FALSE)
  347.     {
  348.         FLTclose(flt);
  349.         return(FALSE);
  350.     }
  351.  
  352.     /* create a new buffer for the output */
  353.     if ((bp = bfind(bname, TRUE, BFINVS)) == FALSE)
  354.     {
  355.         FLTclose(flt);
  356.         return(FALSE);
  357.     }
  358.  
  359.     /* and read the stuff in */
  360.     if (bufread(bp,FLTout(flt)) == FALSE)
  361.     {
  362.         FLTclose(flt);
  363.         return(FALSE);
  364.     }
  365.  
  366.     FLTclose(flt);
  367.  
  368.     /* make this window in VIEW mode, update all mode lines */
  369.     bp->b_mode |= MDVIEW;
  370.     wp = wheadp;
  371.     while (wp != NULL) {
  372.         wp->w_flag |= WFMODE;
  373.         wp = wp->w_wndp;
  374.     }
  375.  
  376.     return(TRUE);
  377. }
  378.  
  379. /*
  380.  * filter a buffer through an external DOS program
  381.  * Bound to ^X #
  382.  */
  383. int filter (int f, int n)
  384. {
  385.         register int s;        /* return status from CLI */
  386.         char line[NLINE];    /* command line send to shell */
  387.     LINE *lp;        /* Temporary line pointer */
  388.     FILTER *flt;        /* Command filter */
  389.     register int i;
  390.  
  391.     /* don't allow this command if restricted */
  392.     if (restflag)
  393.         return(resterr());
  394.  
  395.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  396.         return(rdonly());    /* we are in read only mode    */
  397.  
  398.     if ((flt = FLTopen()) == NULL) {
  399.         mlwrite(TEXT2);
  400. /*                      "[Cannot write filter file]" */
  401.         return(FALSE);
  402.     }
  403.  
  404.     /* get the filter name and its args */
  405.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  406.                 return(s);
  407.  
  408.     /* copy the current buffer into the filter */
  409.     lp = lforw(curbp->b_linep);
  410.  
  411.     while (lp != curbp->b_linep)
  412.     {
  413.         for (i = 0; i < llength(lp); ++i)
  414.             putc(lp->l_text[i], FLTin(flt));
  415.  
  416.         putc('\n', FLTin(flt));
  417.  
  418.         if (ferror(FLTin(flt))) {
  419.             FLTclose(flt);
  420.             mlwrite(TEXT2);
  421. /*                          "[Cannot write filter file]" */
  422.             return(FALSE);
  423.         }
  424.  
  425.         lp = lforw(lp);
  426.     }
  427.  
  428.     movecursor(term.t_nrow - 1, 0);
  429.     TTkclose();
  430.     s = FLTfilter(flt,line);
  431.     TTkopen();
  432.         sgarbf = TRUE;
  433.  
  434.     /* on failure, escape gracefully */
  435.     if (s == FILTER_ERROR || bufread(curbp,FLTout(flt)) == FALSE)
  436.     {
  437.         FLTclose(flt);
  438.         mlwrite(TEXT3);
  439. /*                      "[Execution failed]" */
  440.         return(FALSE);
  441.     }
  442.  
  443.     /* Flag the buffer as changed */
  444.     curbp->b_flag |= BFCHG;
  445.     FLTclose(flt);
  446.  
  447.     return(TRUE);
  448. }
  449.  
  450. /* Read a file from a supplied file pointer into a specified buffer.
  451.  * The buffer's original contents is deleted. FALSE is returned in case
  452.  * of errors, TRUE if the read succeeds.
  453.  */
  454.  
  455. int bufread (BUFFER *bp, FILE *fp)
  456. {
  457.     register LINE *lp1;
  458.     register LINE *lp2;
  459.     register WINDOW *wp;
  460.     register int i;
  461.     register int s;
  462.     int nbytes;
  463.     int nline;
  464.     int cmark;
  465.     char mesg[NSTRING];
  466.     char *tline = NULL;
  467.     int tlen = 0;
  468.  
  469.     if ((s = bclear(bp)) != TRUE)
  470.         return(s);
  471.  
  472.     bp->b_flag &= ~BFCHG;
  473.  
  474.     nline = 0;
  475.  
  476.     while ((s = fgetline(fp, &tline, &tlen)) == FIOSUC)
  477.     {
  478.         nbytes = strlen(tline);
  479.         if ((lp1 = lalloc(nbytes)) == NULL)
  480.         {
  481.             s = FIOMEM;
  482.             break;
  483.         }
  484.         lp2 = lback(bp->b_linep);
  485.         lp2->l_fp = lp1;
  486.         lp1->l_fp = bp->b_linep;
  487.         lp1->l_bp = lp2;
  488.         bp->b_linep->l_bp = lp1;
  489.         for (i = 0; i < nbytes; ++i)
  490.             lputc(lp1, i, tline[i]);
  491.  
  492.         ++nline;
  493.     }
  494.  
  495.     if (tline != NULL)
  496.         free(tline);
  497.  
  498.     strcpy(mesg,"[");
  499.     if (s==FIOERR) {
  500.         strcat(mesg, TEXT141);
  501. /*                           "I/O ERROR, " */
  502.         bp->b_flag |= BFTRUNC;
  503.     }
  504.     if (s == FIOMEM) {
  505.         strcat(mesg, TEXT142);
  506. /*                           "OUT OF MEMORY, " */
  507.         bp->b_flag |= BFTRUNC;
  508.     }
  509.     strcat(mesg, TEXT140);
  510. /*                   "Read " */
  511.     strcat(mesg, int_asc(nline));
  512.     strcat(mesg, TEXT143);
  513. /*                   " line" */
  514.     if (nline > 1)
  515.         strcat(mesg, "s");
  516.     strcat(mesg, "]");
  517.     mlwrite(mesg);
  518.  
  519.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  520.         if (wp->w_bufp == bp) {
  521.             wp->w_linep = lforw(bp->b_linep);
  522.             wp->w_dotp  = lforw(bp->b_linep);
  523.             wp->w_doto  = 0;
  524.             for (cmark = 0; cmark < NMARKS; cmark++) {
  525.                 wp->w_markp[cmark] = NULL;
  526.                 wp->w_marko[cmark] = 0;
  527.             }
  528.             wp->w_flag |= WFMODE|WFHARD;
  529.         }
  530.     }
  531.  
  532.     if (s == FIOERR || s == FIOFNF)     /* False if error.    */
  533.         return(FALSE);
  534.  
  535.     return(TRUE);
  536. }
  537.  
  538. /* Read a line from a file, and store the bytes in the supplied buffer.
  539.  * Check for I/O errors. Return status.
  540.  */
  541. int fgetline(FILE *fp, char **tline, int *tlen)
  542. {
  543.         register int c;        /* current character read */
  544.         register int i;        /* current index into fline */
  545.     register char *tmpline;    /* temp storage for expanding line */
  546.  
  547.     /* internal copies of the parameters */
  548.     register char *tline1 = *tline;
  549.     register int   tlen1  = *tlen;
  550.  
  551.     /* if we are at the end...return it */
  552.     if (feof(fp))
  553.         return(FIOEOF);
  554.  
  555.     /* if we don't have an tline, allocate one */
  556.     if (tline1 == NULL)
  557.         if ((tline1 = malloc(tlen1 = NSTRING)) == NULL)
  558.             return(FIOMEM);
  559.  
  560.     /* read the line in */
  561.         i = 0;
  562.         while ((c = getc(fp)) != EOF && c != '\n') {
  563.                 tline1[i++] = c;
  564.         /* if it's longer, get more room */
  565.                 if (i >= tlen1) {
  566.                     if ((tmpline = malloc(tlen1+NSTRING)) == NULL)
  567.                     {
  568.                         *tline = tline1;
  569.                         *tlen = tlen1;
  570.                         return(FIOMEM);
  571.                     }
  572.                     bytecopy(tmpline, tline1, tlen1);
  573.                     tlen1 += NSTRING;
  574.                     free(tline1);
  575.                     tline1 = tmpline;
  576.                 }
  577.         }
  578.  
  579. #if    ST520
  580.     if (tline1[i-1] == '\r')
  581.         i--;
  582. #endif
  583.  
  584.     /* terminate the string */
  585.         tline1[i] = 0;
  586.  
  587.         /* restore the input variables */
  588.     *tline = tline1;
  589.     *tlen = tlen1;
  590.  
  591.     /* test for any errors that may have occured */
  592.         if (c == EOF) {
  593.                 if (ferror(fp)) {
  594.                         mlwrite(TEXT158);
  595. /*                              "File read error" */
  596.                         return(FIOERR);
  597.                 }
  598.  
  599.                 if (i == 0)
  600.             return(FIOEOF);
  601.         }
  602.  
  603.         return(FIOSUC);
  604. }
  605.  
  606. /* Run an interactive operating system shell */
  607.  
  608. static void shell (void)
  609. {
  610.     int len;
  611.     _kernel_oserror *err;
  612.     char line[261];
  613.  
  614.     strcpy(line, "Call:");
  615.  
  616.     /* Set text window to the full screen */
  617.     vdu(26);
  618.  
  619.     /* Set background colour to green and foreground colour to black
  620.      * (but do it the opposite way round and apply reverse video, to
  621.      * set things up right for 2-colour modes)
  622.      */
  623. #if    COLOR
  624.     TTbacg(0);
  625.     TTforg(2);
  626.     TTrev(TRUE);
  627. #endif
  628.  
  629.     /* Clear screen */
  630.     vdu(12);
  631.  
  632.     /* Centre on line 0 */
  633.     vdu(31);
  634.     vdu((term.t_ncol - 14) / 2);
  635.     vdu(0);
  636.  
  637.     /* Write the screen title */
  638.     regs.r[0] = (int)"Archimedes MOS";
  639.     swi(OS_Write0);
  640.  
  641.     /* Define text window, missing top and bottom lines */
  642.     vdu(28);
  643.     vdu(0);
  644.     vdu(term.t_nrow - 1);
  645.     vdu(term.t_ncol - 1);
  646.     vdu(1);
  647.  
  648.     /* Set background colour to blue and foreground colour to grey */
  649. #if    COLOR
  650.     TTrev(FALSE);
  651.     TTbacg(4);
  652.     TTforg(7);
  653. #endif
  654.  
  655.     /* Clear screen */
  656.     vdu(12);
  657.  
  658.     for (;;)
  659.     {
  660.         vdu('*');
  661.  
  662.         regs.r[0] = (int)&line[5];
  663.         regs.r[1] = 256;
  664.         regs.r[2] = 32;
  665.         regs.r[3] = 255;
  666.  
  667.         /* We can't trap ESCAPE here... it acts just like NL */
  668.         if ((err = swi(OS_ReadLine)) != NULL)
  669.         {
  670.             swi(OS_NewLine);
  671.             regs.r[0] = (int)err->errmess;
  672.             swi(OS_Write0);
  673.             swi(OS_NewLine);
  674.  
  675.             continue;
  676.         }
  677.  
  678.         len = regs.r[1];
  679.  
  680.         if (len == 0)
  681.             break;
  682.  
  683.         line[5+len] = 0;
  684.  
  685.         esc_on();
  686.  
  687.         if (system(line) == -2)
  688.         {
  689.             char buf[300];
  690.  
  691.             err = _kernel_last_oserror();
  692.             sprintf(buf, "%s (Error %d)", err->errmess,
  693.                 err->errnum);
  694.  
  695.             swi(OS_NewLine);
  696.             regs.r[0] = (int)buf;
  697.             swi(OS_Write0);
  698.             swi(OS_NewLine);
  699.         }
  700.  
  701.         esc_off();
  702.     }
  703.  
  704.     /* Restore the default text window */
  705.     vdu(26);
  706. }
  707.  
  708. /* return a system dependent string with the current time */
  709.  
  710. char *timeset (void)
  711. {
  712.     register char *sp;    /* temp string pointer */
  713.     time_t timeval;
  714.  
  715.     time(&timeval);
  716.     sp = ctime(&timeval);
  717.     sp[strlen(sp)-1] = 0;
  718.     return(sp);
  719. }
  720.  
  721. /* Read a single keypress and return it, converting Risc OS character codes
  722.  * into Emacs extended character codes
  723.  */
  724.  
  725. static int extchar (int alt, int c)
  726. {
  727.     int base_key;
  728.     int shft = 0;
  729.     int ctrl = 0;
  730.  
  731. /* Save a bit of typing */
  732. #define asc (alt | shft | ctrl)
  733.  
  734.     /* Break the extended code up into parts */
  735.     base_key = c & 0xCF;
  736.     shft = (c & 0x10 ? SHFT : 0);
  737.     ctrl = (c & 0x20 ? CTRL : 0);
  738.  
  739.     /* F1 to F9 (FN1 - FN9) */
  740.     if (base_key >= 0x81  && base_key <= 0x89)
  741.         return(SPEC | asc | base_key - 0x81 + '1');
  742.  
  743.     switch (base_key)
  744.     {
  745.     case 0x80:    /* F0 (Print) */
  746.             return(SPEC | asc | '`');
  747.  
  748.     case 0xCA:    /* F10 */
  749.             return(SPEC | asc | '0');
  750.  
  751.     case 0xCB:    /* F11 */
  752.             return(SPEC | asc | '-');
  753.  
  754.     case 0xCC:    /* F12 */
  755.             return(SPEC | asc | '=');
  756.  
  757.     case 0x8B:    /* Copy */
  758.             return (SPEC | asc | '>');
  759.  
  760.     case 0x8C:    /* Cursor Left */
  761.             return (SPEC | asc | 'B');
  762.  
  763.     case 0x8D:    /* Cursor Right */
  764.             return (SPEC | asc | 'F');
  765.  
  766.     case 0x8E:    /* Cursor Down */
  767.             return (SPEC | asc | 'N');
  768.  
  769.     case 0x8F:    /* Cursor Up */
  770.             return (SPEC | asc | 'P');
  771.  
  772.     case 0xCD:    /* Insert */
  773.             return (SPEC | asc | 'C');
  774.  
  775.     case 0xC1:    /* Home */
  776.             return (SPEC | asc | '<');
  777.  
  778.     case 0xC2:    /* Page Down */
  779.             return (SPEC | asc | 'V');
  780.  
  781.     case 0xC3:    /* Page Up */
  782.             return (SPEC | asc | 'Z');
  783.  
  784.     case 0xC0:    /* Delete */
  785.         if (asc == 0)
  786.             return ('\x7F');
  787.         else
  788.             return (SPEC | asc | 'D');
  789.  
  790.     case 0x8A:    /* Tab */
  791.         if (asc == 0)
  792.             return ('\t');
  793.         else if (!ctrl)
  794.             return (alt | shft | CTRL | 'I');
  795.         else
  796.             return (SPEC | asc | 'T');        /*?????*/
  797.  
  798.     case 0xC4:    /* Backspace */
  799.         if (asc == 0)
  800.             return ('\b');
  801.         else if (!ctrl)
  802.             return (alt | shft | CTRL | 'H');
  803.         else
  804.             return (SPEC | asc | 'L');        /*?????*/
  805.  
  806.     case 0xC5:    /* Return */
  807.         if (asc == 0)
  808.             return ('\r');
  809.         else if (asc == SHFT)
  810.             return ('\n');
  811.         else
  812.             return (SPEC | asc | 'R');
  813.  
  814.     case 0xC6:    /* Enter */
  815.         if (asc == 0)
  816.             return ('\r');
  817.         else if (asc == SHFT)
  818.             return ('\n');
  819.         else
  820.             return (SPEC | asc | 'E');
  821.     }
  822.  
  823.     /* Anything else, return as itself */
  824.     return (alt | c);
  825.  
  826. #undef asc
  827. }
  828.  
  829. #if    FTYPE
  830. /*     File type routines */
  831.  
  832. void PASCAL NEAR fsettype (char *fname, int type)
  833. {
  834.     regs.r[0] = 18;
  835.     regs.r[1] = (int)fname;
  836.     regs.r[2] = type;
  837.     swi(OS_File);
  838. }
  839.  
  840. int PASCAL NEAR fgettype (char *fname)
  841. {
  842.     regs.r[0] = 5;
  843.     regs.r[1] = (int)fname;
  844.  
  845.     if (swi(OS_File))
  846.         return(0xFFF);
  847.  
  848.     if ((regs.r[2] & 0xFFF00000) != 0xFFF00000)
  849.         return(0xFFF);
  850.  
  851.     return((regs.r[2] >> 8) & 0xFFF);
  852. }
  853.  
  854. int PASCAL NEAR maketype (char *type)
  855. {
  856.     regs.r[0] = 31;
  857.     regs.r[1] = (int)type;
  858.  
  859.     if (swi(OS_FSControl))
  860.         return(0xFFF);
  861.  
  862.     return(regs.r[2]);
  863. }
  864. #endif
  865.  
  866. /*    FILE Directory routines        */
  867.  
  868. /*    do a wild card directory search (for file name completion) */
  869.  
  870. char *getffile (char *fspec)
  871. {
  872.     char fname[NFILEN];        /* file/path for dirscan() call */
  873.     char *name;
  874.     _kernel_osfile_block blk;
  875.  
  876.     /* Add a "*" wildcard at the end */
  877.     strcpy(fname, fspec);
  878.     strcat(fname, "*");
  879.  
  880.     /* Look for the next non-directory name */
  881.     name = dirscan(fname);
  882.     while (name && _kernel_osfile(17,name,&blk) != 1)
  883.         name = dirscan(0);
  884.  
  885.     return (name);
  886. }
  887.  
  888. char *getnfile (void)
  889. {
  890.     char *name;
  891.     _kernel_osfile_block blk;
  892.  
  893.     /* Look for the next non-directory name */
  894.     name = dirscan(0);
  895.     while (name && _kernel_osfile(17,name,&blk) != 1)
  896.         name = dirscan(0);
  897.  
  898.     return (name);
  899. }
  900. #endif
  901.